<template>
  <Cascader
    class="larry-remote-cascader"
    :placeholder="placeholder"
    :value="defaultValue"
    :data="cascaderDatas"
    :load-data="loadAfterData"
    filterable
    :change-on-select="!needSelectLeaf"
    trigger="hover"
    @on-change="handleSelectedChange"
    :clearable="clearable"
    :disabled="disabled"
  />
</template>
<script>
import { Cascader } from "view-design";
import appService from "@/utils/appService";
import config from "@/utils/config";
import compare from "@/utils/compare";
export default {
  props: {
    value: {
      required: false,
      type: [Array, String, Object]
    },
    /** 是否禁用 */
    disabled: {
      type: Boolean,
      default: false
    },
    /** 是否可以删除 */
    clearable: {
      type: Boolean,
      default: false
    },
    /** 查询数据时，往指定的vuex module推送loading状态 */
    namespace: {
      required: false,
      type: String
    },
    /** 需要选择到最后一级 */
    needSelectLeaf: {
      type: Boolean,
      default: false
    },
    placeholder: {
      type: String,
      default: "请选择"
    },
    /** 在返回选项时，是否将原始数据返回，默认只返回 value */
    metaInValue: {
      type: Boolean,
      default: false,
      required: false
    },
    /** 只返回最后一个值 */
    lastValue: {
      type: Boolean,
      default: false,
      required: false
    },
    /** 请求数据接口 */
    api: {
      type: String,
      required: true
    },
    /** 是否需要参数才抓取数据 */
    needQueryParam: {
      type: Boolean,
      default: false,
      required: false
    },
    /** 第一层查询参数 */
    queryParam: {
      type: Object
    },
    /** @see 当存在默认值的时候，第一次可能无法加载对应的选项，所以需要特殊处理默认值的选项。
     * 如果是String类型,查询参数名称为该传入值，参数值是value,仅限于value不是Object的情况下使用;
     * 如果是Function,将调用该函数获取参数，函数传入值为value,返回值应为对象;
     * 如果是Object,传入对象示例{parameName:"parentId",valueKey:"id"}，其中parameName作为参数名称,valueKey作为参数值的取值key,仅限于value是Object的情况下使用. */
    defaultValueQueryParam: {
      type: [String, Function, Object],
      required: false,
      default: "id"
    },
    /** 后续查询参数,如果是String类型，查询参数名称为该传入值，参数值为选中的值;
     * 如果是Function，将调用该函数获取参数，函数传入值为选中项，返回值应为对象;
     * 如果是Object,传入对象示例{parameName:"parentId",valueKey:"id"}，其中parameName作为参数名称,valueKey作为参数值的取值key */
    afterQueryParam: {
      type: [String, Function, Object],
      required: true
    },
    /** 树加载深度, 不填时将会一直加载直到没有叶子节点,当填写时,加载深度等于该值时,将不再加载子节点 */
    depth: {
      type: Number,
      required: false
    },
    /** 展示字段的key */
    labelKey: {
      default: "name",
      type: String
    },
    /** 选中项值的key */
    valueKey: {
      default: "id",
      type: String
    }
  },
  components: { Cascader },
  model: {
    prop: "value",
    event: "onChange"
  },
  data: function() {
    return {
      cascaderDatas: [],
      /** 是否已经加载了默认数据 */
      loadedDefaultData: false
    };
  },
  computed: {
    defaultValue: function() {
      let value = this.value;
      if (!value) {
        return [];
      }
      if (value instanceof Array) {
        let result = [];
        for (let i = 0; i < value.length; i++) {
          if (value[i] instanceof Object) {
            result.push(value[i].id);
          } else {
            result.push(value[i]);
          }
        }
        return result;
      } else {
        let result = [];
        if (value instanceof Object) {
          result.push(value.id);
        } else {
          result.push(value);
        }
        return result;
      }
    }
  },
  watch: {
    api: function(newValue, oldValue) {
      if (!compare(newValue, oldValue)) {
        this.loadInitData();
      }
    },
    queryParam: function(newValue, oldValue) {
      if (!compare(newValue, oldValue)) {
        this.loadInitData();
      }
    },
    value(newValue, oldValue) {
      if (!this.selfChange) {
        this.loadDefaultData();
      }
      this.selfChange = false;
    }
  },
  beforeMount: async function() {
    this.loadInitData();
  },
  methods: {
    /** 加载初始数据 */
    async loadInitData() {
      this.loadedDefaultData = false;
      if (this.$props.api) {
        if (this.needQueryParam && !this.queryParam) {
          return;
        }
        this.loading = true;
        if (this.namespace) {
          this.$store.commit(`${namespace}/saveState`, { loading: true });
        }
        let responst = await appService.getRequest(
          this.$props.api,
          this.$props.queryParam
        );
        this.loading = false;
        /** 关闭vuex loading状态 */
        if (this.namespace) {
          this.$store.commit(`${namespace}/saveState`, { loading: false });
        }
        if (responst.status === 200 && responst.data.errorCode === 0) {
          let datas = responst.data.data;
          let cascaderDatas = [];
          for (let i = 0; i < datas.length; i++) {
            let node = {
              value: datas[i][this.valueKey],
              label: datas[i][this.labelKey],
              children: [],
              loading: false,
              metaData: datas[i]
            };
            if (this.depth && this.depth === 1) {
              delete node.loading;
              delete node.children;
            }
            cascaderDatas.push(node);
            let defaultValue = this.defaultValue;
            if (defaultValue.length > 0) {
              if (node.value === defaultValue[defaultValue.length - 1]) {
                this.loadedDefaultData = true;
              }
            }
          }
          this.cascaderDatas = cascaderDatas;
        }
      }
      if (!this.loadedDefaultData) {
        await this.loadDefaultData();
      }
    },
    /** 加载默认数据 */
    async loadDefaultData() {
      let needHandleValue;
      if (this.value) {
        if (!(this.value instanceof Array)) {
          needHandleValue = this.value;
        } else {
          if (this.value.length === 1) {
            needHandleValue = this.value[0];
          }
        }
      }
      /** 如果默认值只有一个时才需要处理 */
      if (needHandleValue) {
        /** 判断首次加载上来的数据是否已经包含了该默认值 */
        let cascaderDatas = this.cascaderDatas;
        let realValue = needHandleValue;
        if (needHandleValue instanceof Object) {
          realValue = realValue[this.valueKey];
        }
        for (let i = 0; i < cascaderDatas.length; i++) {
          if (cascaderDatas[i][this.valueKey] === realValue) {
            this.loadedDefaultData = true;
            return;
          }
        }
        /** 如果没有加载到默认值,进行后续的处理 */
        let queryParam;
        if (typeof this.defaultValueQueryParam === "string") {
          queryParam = {};
          queryParam[this.defaultValueQueryParam] = this.value;
        } else if (this.defaultValueQueryParam instanceof Function) {
          queryParam = this.defaultValueQueryParam(this.value);
        } else if (this.defaultValueQueryParam instanceof Object) {
          queryParam = {};
          queryParam[this.defaultValueQueryParam.parameName] = this.value[
            this.defaultValueQueryParam.valueKey
          ];
        }
        if (queryParam) {
          this.loading = true;
          if (this.namespace) {
            this.$store.commit(`${namespace}/saveState`, { loading: true });
          }
          let responst = await appService.getRequest(
            this.$props.api,
            queryParam
          );
          this.loading = false;
          /** 关闭vuex loading状态 */
          if (this.namespace) {
            this.$store.commit(`${namespace}/saveState`, { loading: false });
          }
          if (responst.status === 200 && responst.data.errorCode === 0) {
            let datas = responst.data.data;
            let cascaderDatas = [];
            for (let i = 0; i < datas.length; i++) {
              cascaderDatas.push({
                value: datas[i][this.valueKey],
                label: datas[i][this.labelKey],
                children: [],
                metaData: datas[i]
              });
            }
            this.cascaderDatas = this.cascaderDatas.concat(cascaderDatas);
          }
        }
      }
    },
    /** 加载后续数据 */
    async loadAfterData(item, callback) {
      let depth = item.__value.split(",").length;
      let metaData = item.metaData;
      let queryParam;
      if (typeof this.afterQueryParam === "string") {
        queryParam = {};
        queryParam[this.afterQueryParam] = item.value;
      } else if (this.afterQueryParam instanceof Function) {
        queryParam = this.afterQueryParam(metaData);
      } else if (this.afterQueryParam instanceof Object) {
        queryParam = {};
        queryParam[this.afterQueryParam.parameName] =
          metaData[this.afterQueryParam.valueKey];
      }
      if (queryParam) {
        item.loading = true;
        if (this.namespace) {
          this.$store.commit(`${namespace}/saveState`, { loading: true });
        }
        let responst = await appService.getRequest(this.$props.api, queryParam);
        /** 关闭vuex loading状态 */
        if (this.namespace) {
          this.$store.commit(`${namespace}/saveState`, { loading: false });
        }
        if (responst.status === 200 && responst.data.errorCode === 0) {
          let datas = responst.data.data;
          /** 有后续层级的数据 */
          if (datas && datas.length > 0) {
            let newDistricts = [];
            for (let i = 0; i < datas.length; i++) {
              let node = {
                value: datas[i][this.valueKey],
                label: datas[i][this.labelKey],
                children: [],
                loading: false,
                metaData: datas[i]
              };
              //如果加载层数达到
              if (this.depth && depth + 1 === this.depth) {
                delete node.loading;
                delete node.children;
              }
              newDistricts.push(node);
            }
            item.children = newDistricts;
            item.loading = false;
            /** 移除处理的默认数据 */
            if (!this.loadedDefaultData) {
              let needHandleValue;
              if (this.value) {
                if (!(this.value instanceof Array)) {
                  needHandleValue = this.value;
                } else {
                  if (this.value.length === 1) {
                    needHandleValue = this.value[0];
                  }
                }
              }
              /** 如果默认值只有一个时才需要处理 */
              if (needHandleValue) {
                /** 判断本次加载上来的数据是否已经包含了该默认值 */
                let realValue = needHandleValue;
                if (needHandleValue instanceof Object) {
                  realValue = realValue[this.valueKey];
                }
                for (let i = 0; i < newDistricts.length; i++) {
                  if (newDistricts[i].value === realValue) {
                    this.loadedDefaultData = true;
                    break;
                  }
                }
                /** 从第一层数据中删除默认的数据 */
                if (this.loadedDefaultData) {
                  let cascaderDatas = this.cascaderDatas;
                  for (let i = 0; i < cascaderDatas.length; i++) {
                    let cascaderData = cascaderDatas[i];
                    if (cascaderData.value === realValue) {
                      cascaderDatas.splice(i, 1);
                      this.cascaderDatas = cascaderDatas;
                      break;
                    }
                  }
                }
              }
            }
          } else {
            /** 没有后续层级的数据 */
            item.children = [];
            item.loading = false;
            delete item.loading;
          }
        } else {
          /** 网络错误,管理loading */
          item.loading = false;
        }
      }
      callback();
    },
    handleSelectedChange(value, selectedData) {
      let result = [];
      for (let i = 0; i < selectedData.length; i++) {
        result.push(selectedData[i].metaData);
      }
      this.selfChange = true;
      if (this.metaInValue) {
        if (!this.lastValue) {
          this.$emit("onChange", result.pop(), value);
        } else {
          this.$emit("onChange", result, value);
        }
      } else {
        if (!this.lastValue) {
          this.$emit("onChange", value, result);
        } else {
          this.$emit("onChange", value.pop(), result);
        }
      }
    }
  }
};
</script>
<style lang="less">
.larry-remote-cascader {
  display: inline-block;
  width: 100%;
}
</style>
